﻿using ArcFaceDemo.ArcFace;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using static ArcFaceDemo.ArcFace.FaceDllImport;

namespace ArcFaceDemo
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        //使用内存 40M
        int detectSize = 40 * 1024 * 1024;
        int nScale = 50;
        int nMaxFaceNum = 10;
        string appId = "8ixc4R2Lp86xUcPpEur4s14vUupi4YLQMLuG9fEZ5oav";
        string sdkFDKey = "AutD8xLbYRCGWesWSUNj1rascg8bj7metF22djhwm3mG";
        IntPtr detectEngine = IntPtr.Zero;
        /// <summary>
        /// 初始化引擎
        /// </summary>
        /// <returns></returns>
        private int InitAgeEstimate()
        {
            var pMem = Marshal.AllocHGlobal(detectSize);
            int retCode = FaceDllImport.ASAE_FSDK_InitAgeEngine(appId, sdkFDKey, pMem, detectSize, ref detectEngine);
            return retCode;
        }

        //释放内存资源
        private int UnInitAgeEstimate()
        {
            if (detectEngine != IntPtr.Zero)
            {
                 return  FaceDllImport.ASAE_FSDK_UninitAgeEngine(detectEngine);
            }
            return -1;
        }
        /// <summary>
        /// 输出信息版本信息
        /// </summary>
        private string PrintVersionInfo()
        {
            if (detectEngine != IntPtr.Zero)
            {
                IntPtr  pVersion  = FaceDllImport.ASAE_FSDK_GetVersion(detectEngine);
                //aSAE_FSDK_Version.lBuild = 0;
                ASAE_FSDK_Version aSAE_FSDK_Version = (ASAE_FSDK_Version)Marshal.PtrToStructure(pVersion,typeof(ASAE_FSDK_Version));
                return Marshal.PtrToStringAnsi(aSAE_FSDK_Version.Version);
            }
            return null;
        }

        /// <summary>
        /// 年龄检测
        /// </summary>
        /// <returns></returns>
        private int AgeEstimate()
        {
            if (detectEngine!= IntPtr.Zero && image!=null)
            {
                //复制图像数据AllocHGlobal
                byte[] imageData = bitmapimagetobytearray(image);
                IntPtr imageDataPtr = Marshal.AllocHGlobal(imageData.Length);
                Marshal.Copy(imageData, 0, imageDataPtr, imageData.Length);


                //return ArcFace.AgeEstimation.ASAE_FSDK_AgeEstimation_StaticImage(detectEngine, imageDataPtr,);
            }


            return -1;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var retCode = InitAgeEstimate();

                if (retCode != 0)
                {
                    System.Windows.MessageBox.Show("引擎初始化失败:错误码为:" + retCode);
                    this.Close();
                }
                var info = PrintVersionInfo();
                this.Title = info;
                UnInitAgeEstimate();
            }
            catch (Exception ex)
            {

                System.Windows.MessageBox.Show(ex.ToString());
            }
        }

        private byte[] readBmp(Bitmap image, ref int width, ref int height, ref int pitch)
        {//将Bitmap锁定到系统内存中,获得BitmapData
            BitmapData data = image.LockBits(new System.Drawing.Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            //位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行
            IntPtr ptr = data.Scan0;
            //定义数组长度
            int soureBitArrayLength = data.Height * Math.Abs(data.Stride);
            byte[] sourceBitArray = new byte[soureBitArrayLength];
            //将bitmap中的内容拷贝到ptr_bgr数组中
            Marshal.Copy(ptr, sourceBitArray, 0, soureBitArrayLength);
            width = data.Width;
            height = data.Height;
            pitch = Math.Abs(data.Stride);//每一行宽度

            int line = width * 3;
            int bgr_len = line * height;
            byte[] destBitArray = new byte[bgr_len];
            for (int i = 0; i < height; ++i)
            {
                Array.Copy(sourceBitArray, i * pitch, destBitArray, i * line, line);
            }
            pitch = line;
            image.UnlockBits(data);
            return destBitArray;
        }

        public static byte[] bitmapimagetobytearray(BitmapImage bmp)
        {
            byte[] bytearray = null;

            try
            {
                JpegBitmapEncoder encoder = new JpegBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(bmp));
                using (MemoryStream ms = new MemoryStream())
                {
                    encoder.Save(ms);
                    bytearray = ms.ToArray();
                }
            }
            catch(Exception ex)
            {
                System.Windows.MessageBox.Show(ex.ToString());
                //other exception handling
            }

            return bytearray;
        }
        BitmapImage image = null;

        Bitmap bitmap = null;
        private void btnImgOpen_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openFile = new OpenFileDialog();
            openFile.Filter = "图片文件|*.bmp;*.jpg;*.jpeg;*.png|所有文件|*.*;";
            openFile.Multiselect = false;
            openFile.FileName = "";
            if (openFile.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                //ImageSourceConverter.Equals
                image = new BitmapImage(new Uri(openFile.FileName));
                imgSrc.Source = image;
                //TODO:完成下面的方法
                //checkAndMarkFace(this.pictureBox1.Image);

                bitmap =  (Bitmap)Bitmap.FromFile(openFile.FileName);
            }
        }

        /// <summary>
        /// 人脸检测 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnFaceDetection_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (image==null)
                {
                    System.Windows.MessageBox.Show("请打开图像!");
                    return;
                }
                IntPtr detectEngine = IntPtr.Zero;
                int detectSize = 40 * 1024 * 1024;
                int nScale = 50; //最小人脸大小
                int nMaxFaceNum = 16; //检测出的人脸数
                //官网申请
                string appId = "8ixc4R2Lp86xUcPpEur4s14vUupi4YLQMLuG9fEZ5oav"; 
                string sdkFDKey = "AutD8xLbYRCGWesWSUNj1ra8eGZaAd5Be42zmQowtvJa";

                var pMem = Marshal.AllocHGlobal(detectSize);
                int retCode = FaceDllImport.AFD_FSDK_InitialFaceEngine(appId, sdkFDKey, pMem, detectSize, ref detectEngine,
                    (int)AFD_FSDK_OrientPriority.AFD_FSDK_OPF_0_HIGHER_EXT, nScale, nMaxFaceNum);
                if (retCode != 0)
                {
                    System.Windows.MessageBox.Show("引擎初始化失败:错误码为:" + retCode);
                    this.Close();
                }

                //获取版本号信息
                IntPtr pVersion = FaceDllImport.AFD_FSDK_GetVersion(detectEngine);
                //aSAE_FSDK_Version.lBuild = 0;
                AFD_FSDK_Version aSAE_FSDK_Version = (AFD_FSDK_Version)Marshal.PtrToStructure(pVersion, typeof(AFD_FSDK_Version));
                this.Title =  Marshal.PtrToStringAnsi(aSAE_FSDK_Version.Version) + Marshal.PtrToStringAnsi(aSAE_FSDK_Version.BuildDate);

                ///加载图像

                //byte[] imageData = bitmapimagetobytearray(image);
                int width = 0, height=0, pitch=0;
                byte[] imageData = readBmp(bitmap, ref width, ref height, ref pitch);

                IntPtr imageDataPtr = Marshal.AllocHGlobal(imageData.Length);
                Marshal.Copy(imageData, 0, imageDataPtr, imageData.Length);

                ASVLOFFSCREEN offInput = new ASVLOFFSCREEN();
                offInput.u32PixelArrayFormat = 513;
                offInput.ppu8Plane = new IntPtr[4];
                offInput.ppu8Plane[0] = imageDataPtr;
                offInput.i32Width = width;
                offInput.i32Height = height;
                offInput.pi32Pitch = new int[4];
                offInput.pi32Pitch[0] = pitch;

                IntPtr offInputPtr = Marshal.AllocHGlobal(Marshal.SizeOf(offInput));
                Marshal.StructureToPtr(offInput, offInputPtr, true);

                AFD_FSDK_FACERES faceRes = new AFD_FSDK_FACERES();

                IntPtr faceResPtr = Marshal.AllocHGlobal(Marshal.SizeOf(faceRes));

                int detectResult = FaceDllImport.AFD_FSDK_StillImageFaceDetection(detectEngine, offInputPtr , ref faceResPtr);
                if (detectResult==0)
                {
                    faceRes = (AFD_FSDK_FACERES)Marshal.PtrToStructure(faceResPtr, typeof(AFD_FSDK_FACERES));

                    System.Windows.MessageBox.Show("检测人脸数:" + faceRes.nFace);

                    int size = Marshal.SizeOf(new MRECT());
                    Graphics g = Graphics.FromImage(bitmap);
                    //遍历指针 
                    for (int i = 0; i < faceRes.nFace; i++)
                    {
                        int p = i * size;
                        MRECT rect = (MRECT)Marshal.PtrToStructure(faceRes.rcFace+p, typeof(MRECT));
                        g.DrawRectangle(Pens.Red,new System.Drawing.Rectangle(rect.left,rect.top,rect.right-rect.left,rect.bottom-rect.top));
                       
                        Console.WriteLine(string.Format("当前:{0},rect({1},{2},{3},{4})",i,rect.left,rect.top,rect.right,rect.bottom));
                    }
                    g.Dispose();

                    this.imgSrc.Source = BitmapToBitmapImage(bitmap);

                }

                //释放资源
                FaceDllImport.AFD_FSDK_UninitialFaceEngine(detectEngine);
            }
            catch (Exception ex)
            {

                System.Windows.MessageBox.Show(ex.ToString());
            }
            
        }

        public BitmapImage BitmapToBitmapImage(Bitmap bitmap)
        {
            Bitmap bitmapSource = new Bitmap(bitmap.Width, bitmap.Height);
            int i, j;
            for (i = 0; i < bitmap.Width; i++)
                for (j = 0; j < bitmap.Height; j++)
                {
                    System.Drawing.Color pixelColor = bitmap.GetPixel(i, j);
                    System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixelColor.R, pixelColor.G, pixelColor.B);
                    bitmapSource.SetPixel(i, j, newColor);
                }
            MemoryStream ms = new MemoryStream();
            bitmapSource.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.StreamSource = new MemoryStream(ms.ToArray());
            bitmapImage.EndInit();

            return bitmapImage;
        }
    }
}
